Skip to content

The logo goes on every clip, the outro plays whole, and a guest has a name - #148

Open
nmbrthirteen wants to merge 1 commit into
mainfrom
clip-look-fixes
Open

The logo goes on every clip, the outro plays whole, and a guest has a name#148
nmbrthirteen wants to merge 1 commit into
mainfrom
clip-look-fixes

Conversation

@nmbrthirteen

@nmbrthirteen nmbrthirteen commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Four fixes, all measured against a published Deeptech Decoded short that was cut with this renderer. None needed a new feature; each was the renderer not doing what it was told.

--logo was dropped on three of four caption styles

Two gates: a logo_support flag in the style config that only branded set true, and the logo being drawn inside the branded caption component. So the flag was accepted, the asset resolved, and the watermark silently never drawn on hormozi, karaoke or subtle.

A logo belongs to the show, not to a caption style. Both gates are gone and the mark moved one level up into CaptionedClip, at exactly its old position and size.

A branded render is byte-identical — same frame hash before and after (6bba026c…).

Subtle captions faded in and then cut

Every chunk boundary flickered: the outgoing line vanished on the frame the incoming one started at zero. They ramp down inside their own window now, which crossfades without moving a single caption timing. Skipped on chunks too short to hold full opacity.

An intro or outro was joined through 0.8s of black

concat_outro defaulted to crossfade_duration=0.8, transition="fadeblack" and generate_clip never overrode it, so it ate three quarters of a second of both sides. Measured: 6s of clip + 2s of outro came out at 7.23s.

A designed bookend should be cut to. The fade is a number now (--bookend-fade) and defaults to none — 8.03s for the same inputs.

A clip opens on a stranger

New lower third: name, role, an accent underline, gone after three seconds. --name-card "Jamie Gull: Founder & Solo GP" --name-card-sub "at Wave Function Ventures".

Tests

Two regressions, because this class of bug is silent:

  • no caption style may carry a logo_support gate (fails if a per-style opt-out returns)
  • the name card reaches the renderer's argv

The existing suite already caught a live mistake in this branch: a parameter used in a body whose signature never got it, swallowed by the surrounding except, which showed up only as two subprocess calls instead of four.

test_ai_fallback's three CLI-discovery failures are pre-existing on main and unrelated.

Summary by CodeRabbit

  • New Features

    • Added configurable speaker name cards with title, subtitle, display duration, accent color, and animated fade effects.
    • Added configurable intro and outro crossfades for smoother video transitions.
    • Logos and watermarks now render consistently across caption styles.
    • Caption animations include improved fade-in and fade-out behavior.
  • Bug Fixes

    • Improved branded caption rendering and logo handling.
  • Tests

    • Added coverage for name-card settings, logo rendering, and video transition options.

… name

Four things measured against a published short that was cut with this very
renderer. None of them needed a new feature; all four were the renderer not
doing what it was told.

`--logo` was accepted, resolved from the asset store, and then dropped
unless the caption style happened to be "branded". Two gates did it: a
`logo_support` flag in the style config, and the fact that the logo was
drawn inside the branded caption component. A logo belongs to the show, not
to a caption style. Both gates are gone, the mark moved one level up into
CaptionedClip at exactly its old position, and a branded render is
byte-identical, frame hash for frame hash.

Subtle captions faded in and then cut, so every chunk boundary flickered:
the outgoing line vanished on the frame the incoming one started at zero.
They now ramp down inside their own window, which crossfades without moving
a single caption timing. Skipped on chunks too short to hold full opacity.

An intro or an outro was joined with 0.8 seconds of crossfade through
black, which ate three quarters of a second of both. Six seconds of clip
plus two of outro came out at 7.23. A designed bookend should be cut to;
the fade is now a number, and it defaults to none.

And a clip lifted out of an hour of conversation opens on a stranger, so
there is a lower third: name, role, an accent underline, gone after three
seconds. `--name-card`, `--name-card-sub`.

Two regression tests, because this class of bug is silent: one asserts no
caption style may gate the logo, the other that the name card reaches the
renderer at all. The suite already caught one live mistake here — a
parameter used in a body whose signature never got it, swallowed by the
surrounding except.
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds process options for speaker name cards and bookend fades. It forwards these settings through clip generation into Remotion, adds animated name-card and watermark components, removes style-based logo gating, and updates caption fade behavior.

Changes

Clip rendering enhancements

Layer / File(s) Summary
Pipeline configuration and rendering
backend/cli.py, backend/services/clip_generator.py, tests/test_clip_generator.py
The process command accepts name-card and bookend-fade settings. generate_clip forwards these values to Remotion and applies the fade during intro and outro concatenation. Tests verify logo forwarding and name-card serialization.
Remotion name-card contract and rendering
remotion/render.mjs, remotion/src/Root.tsx, remotion/src/CaptionedClip.tsx, remotion/src/components/NameCard.tsx
Remotion receives an optional nameCard object. CaptionedClip renders the animated lower third when a title is present.
Caption visuals, watermark, and motion
remotion/src/CaptionedClip.tsx, remotion/src/components/Watermark.tsx, remotion/src/components/BrandedCaptions.tsx, remotion/src/components/SubtleCaptions.tsx, remotion/src/motion.ts, backend/config/caption_styles.py
Watermark rendering is centralized. Branded captions no longer render logos directly. Caption styles no longer define logo_support, and subtle captions use the shared fadeInOut helper.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately highlights logo rendering, outro behavior, and the new guest name card, which are central changes in the pull request.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch clip-look-fixes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
tests/test_clip_generator.py (1)

99-107: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the complete name-card command contract.

The test does not pass or assert seconds and accent. A regression that drops either --name-card-seconds or --name-card-accent will pass this test.

Add both values to name_card. Assert that each flag and serialized value reaches the command.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_clip_generator.py` around lines 99 - 107, Update
test_name_card_reaches_the_renderer to include representative seconds and accent
values in name_card, then assert that --name-card-seconds and --name-card-accent
and their serialized values are present in argv alongside the existing title and
subtitle assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/cli.py`:
- Around line 1067-1068: Update every interactive re-render generate_clip call
to pass the same config.get("name_card") and config.get("bookend_fade", 0.0)
values already used by the initial render, preserving overlay settings after
review edits.
- Around line 585-586: Update the --bookend-fade argument definition to use
default=None, preserving the existing args.bookend_fade is not None guard in the
configuration update so preset bookend_fade values are overridden only when the
CLI option is explicitly supplied.

In `@backend/services/clip_generator.py`:
- Around line 923-924: Update the ASS fallback path around the clip-generation
logic at lines 934-958 so a supplied name_card is rendered as an equivalent
lower-third overlay. Ensure this applies when use_ass_captions is enabled and
when Remotion falls back to ASS, including --fast; if ASS cannot support
name_card, reject the option combination before generating a clip rather than
silently omitting it.

In `@remotion/src/components/NameCard.tsx`:
- Around line 41-44: Update the rendering logic in NameCard around fadeInOut so
frames at or beyond seconds * fps return null, ensuring the card unmounts at its
configured duration. Also validate or clamp seconds so durations shorter than
the fade ramps cannot produce unsupported fade behavior.

---

Nitpick comments:
In `@tests/test_clip_generator.py`:
- Around line 99-107: Update test_name_card_reaches_the_renderer to include
representative seconds and accent values in name_card, then assert that
--name-card-seconds and --name-card-accent and their serialized values are
present in argv alongside the existing title and subtitle assertions.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 33715186-0115-435c-b030-4a696fb0f039

📥 Commits

Reviewing files that changed from the base of the PR and between a87c596 and 5d614ed.

📒 Files selected for processing (12)
  • backend/cli.py
  • backend/config/caption_styles.py
  • backend/services/clip_generator.py
  • remotion/render.mjs
  • remotion/src/CaptionedClip.tsx
  • remotion/src/Root.tsx
  • remotion/src/components/BrandedCaptions.tsx
  • remotion/src/components/NameCard.tsx
  • remotion/src/components/SubtleCaptions.tsx
  • remotion/src/components/Watermark.tsx
  • remotion/src/motion.ts
  • tests/test_clip_generator.py
💤 Files with no reviewable changes (2)
  • backend/config/caption_styles.py
  • remotion/src/components/BrandedCaptions.tsx

Comment thread backend/cli.py
Comment on lines +585 to +586
if getattr(args, "bookend_fade", None) is not None:
config["bookend_fade"] = args.bookend_fade

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not overwrite the preset fade when the option is absent.

--bookend-fade defaults to 0.0. Therefore Line 585 always replaces a preset bookend_fade value with a hard cut.

Use default=None in the argument definition. Keep the existing is not None check so only an explicit CLI option overrides the preset.

Proposed fix
-proc.add_argument("--bookend-fade", dest="bookend_fade", type=float, default=0.0,
+proc.add_argument("--bookend-fade", dest="bookend_fade", type=float, default=None,
                   help="Seconds of crossfade into an intro or outro (default 0, a cut)")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/cli.py` around lines 585 - 586, Update the --bookend-fade argument
definition to use default=None, preserving the existing args.bookend_fade is not
None guard in the configuration update so preset bookend_fade values are
overridden only when the CLI option is explicitly supplied.

Comment thread backend/cli.py
Comment on lines +1067 to +1068
name_card=config.get("name_card"),
bookend_fade=config.get("bookend_fade", 0.0),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Forward overlay settings during re-renders.

The initial render receives name_card and bookend_fade. The interactive re-render at Lines 1270-1287 omits both arguments. After any review edit, the replacement clip loses the name card and reverts bookend joins to a hard cut.

Pass the same two configuration values to every re-render generate_clip call.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/cli.py` around lines 1067 - 1068, Update every interactive re-render
generate_clip call to pass the same config.get("name_card") and
config.get("bookend_fade", 0.0) values already used by the initial render,
preserving overlay settings after review edits.

Comment on lines +923 to +924
logo_path=logo_path or None,
name_card=name_card,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Do not silently drop name_card on the ASS render path.

name_card is sent only to Remotion. If use_ass_captions is enabled, or Remotion fails and ASS fallback is allowed, Lines 934-958 emit a clip without the requested lower third. --fast enables this path.

Render an equivalent name card in the fallback path. If that is not supported, reject this option combination instead of producing a clip that omits the requested overlay.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/services/clip_generator.py` around lines 923 - 924, Update the ASS
fallback path around the clip-generation logic at lines 934-958 so a supplied
name_card is rendered as an equivalent lower-third overlay. Ensure this applies
when use_ass_captions is enabled and when Remotion falls back to ASS, including
--fast; if ASS cannot support name_card, reject the option combination before
generating a clip rather than silently omitting it.

Comment on lines +41 to +44
const opacity = fadeInOut({
frame, fps, start: 0, end: seconds, inFrames: 8, outFrames: 10,
});
if (opacity <= 0) return null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Unmount the card after its configured duration.

If seconds is shorter than the fade ramps, fadeInOut() returns the rising opacity only. After it reaches 1, this component remains visible for the rest of the clip instead of ending at seconds.

Check the current frame against seconds * fps before rendering. Also validate or clamp unsupported short durations.

Proposed fix
   const opacity = fadeInOut({
     frame, fps, start: 0, end: seconds, inFrames: 8, outFrames: 10,
   });
-  if (opacity <= 0) return null;
+  if (frame >= Math.round(seconds * fps) || opacity <= 0) return null;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const opacity = fadeInOut({
frame, fps, start: 0, end: seconds, inFrames: 8, outFrames: 10,
});
if (opacity <= 0) return null;
const opacity = fadeInOut({
frame, fps, start: 0, end: seconds, inFrames: 8, outFrames: 10,
});
if (frame >= Math.round(seconds * fps) || opacity <= 0) return null;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@remotion/src/components/NameCard.tsx` around lines 41 - 44, Update the
rendering logic in NameCard around fadeInOut so frames at or beyond seconds *
fps return null, ensuring the card unmounts at its configured duration. Also
validate or clamp seconds so durations shorter than the fade ramps cannot
produce unsupported fade behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant